from fastapi import APIRouter, Depends, HTTPException, status, Query, BackgroundTasks
from sqlalchemy.orm import Session
from typing import List, Optional
from datetime import datetime
import uuid

from app.core.database import get_db
from app.core.security import get_current_active_user
from app.models.user import User
from app.models.release import Release, ReleaseLog, DeploymentConfig
from app.schemas.release import (
    Release as ReleaseSchema,
    ReleaseLog as ReleaseLogSchema,
    DeploymentConfig as DeploymentConfigSchema,
    ReleaseCreate,
    ReleaseUpdate,
    DeploymentConfigCreate
)

router = APIRouter()

@router.get("/releases", response_model=List[ReleaseSchema], summary="获取版本发布列表")
async def get_releases(
    skip: int = Query(0, ge=0, description="跳过记录数"),
    limit: int = Query(20, ge=1, le=100, description="返回记录数"),
    status: Optional[str] = Query(None, description="发布状态"),
    environment: Optional[str] = Query(None, description="部署环境"),
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    获取版本发布列表
    """
    # 检查权限
    if not current_user.has_permission("release:read") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限查看版本发布信息"
        )
    
    query = db.query(Release)
    
    if status:
        query = query.filter(Release.status == status)
    if environment:
        query = query.filter(Release.environment == environment)
    
    releases = query.order_by(Release.created_at.desc()).offset(skip).limit(limit).all()
    
    return [ReleaseSchema.from_orm(release) for release in releases]

@router.post("/releases", response_model=ReleaseSchema, summary="创建版本发布")
async def create_release(
    release_data: ReleaseCreate,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    创建新的版本发布
    """
    # 检查权限
    if not current_user.has_permission("release:create") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限创建版本发布"
        )
    
    # 生成版本号（如果未提供）
    if not release_data.version:
        latest_release = db.query(Release).filter(
            Release.project_name == release_data.project_name
        ).order_by(Release.created_at.desc()).first()
        
        if latest_release:
            # 自动递增版本号
            version_parts = latest_release.version.split('.')
            if len(version_parts) == 3:
                patch = int(version_parts[2]) + 1
                version = f"{version_parts[0]}.{version_parts[1]}.{patch}"
            else:
                version = "1.0.1"
        else:
            version = "1.0.0"
    else:
        version = release_data.version
    
    # 创建发布记录
    release = Release(
        release_id=str(uuid.uuid4()),
        project_name=release_data.project_name,
        version=version,
        environment=release_data.environment,
        branch=release_data.branch,
        commit_hash=release_data.commit_hash,
        description=release_data.description,
        release_notes=release_data.release_notes,
        created_by=current_user.id,
        status="pending",
        strategy=release_data.strategy or "rolling",
        rollback_version=release_data.rollback_version
    )
    
    db.add(release)
    db.commit()
    db.refresh(release)
    
    # 记录发布日志
    log = ReleaseLog(
        release_id=release.id,
        action="created",
        message=f"版本 {version} 发布任务已创建",
        user_id=current_user.id,
        status="info"
    )
    db.add(log)
    db.commit()
    
    # 后台执行部署任务
    if release_data.auto_deploy:
        background_tasks.add_task(execute_deployment, release.id, db)
    
    return ReleaseSchema.from_orm(release)

@router.get("/releases/{release_id}", response_model=ReleaseSchema, summary="获取版本发布详情")
async def get_release(
    release_id: str,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    获取指定版本发布的详细信息
    """
    # 检查权限
    if not current_user.has_permission("release:read") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限查看版本发布信息"
        )
    
    release = db.query(Release).filter(Release.release_id == release_id).first()
    
    if not release:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="版本发布不存在"
        )
    
    return ReleaseSchema.from_orm(release)

@router.put("/releases/{release_id}", response_model=ReleaseSchema, summary="更新版本发布")
async def update_release(
    release_id: str,
    release_data: ReleaseUpdate,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    更新版本发布信息
    """
    # 检查权限
    if not current_user.has_permission("release:update") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限更新版本发布"
        )
    
    release = db.query(Release).filter(Release.release_id == release_id).first()
    
    if not release:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="版本发布不存在"
        )
    
    # 更新字段
    update_data = release_data.dict(exclude_unset=True)
    for field, value in update_data.items():
        setattr(release, field, value)
    
    release.updated_at = datetime.utcnow()
    
    db.commit()
    db.refresh(release)
    
    # 记录更新日志
    log = ReleaseLog(
        release_id=release.id,
        action="updated",
        message=f"版本发布信息已更新",
        user_id=current_user.id,
        status="info"
    )
    db.add(log)
    db.commit()
    
    return ReleaseSchema.from_orm(release)

@router.post("/releases/{release_id}/deploy", summary="执行部署")
async def deploy_release(
    release_id: str,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    执行版本部署
    """
    # 检查权限
    if not current_user.has_permission("release:deploy") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限执行部署"
        )
    
    release = db.query(Release).filter(Release.release_id == release_id).first()
    
    if not release:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="版本发布不存在"
        )
    
    if release.status not in ["pending", "failed"]:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="当前状态不允许部署"
        )
    
    # 更新状态为部署中
    release.status = "deploying"
    release.deployed_by = current_user.id
    release.deployed_at = datetime.utcnow()
    
    db.commit()
    
    # 记录部署开始日志
    log = ReleaseLog(
        release_id=release.id,
        action="deploy_started",
        message=f"开始部署版本 {release.version}",
        user_id=current_user.id,
        status="info"
    )
    db.add(log)
    db.commit()
    
    # 后台执行部署任务
    background_tasks.add_task(execute_deployment, release.id, db)
    
    return {"message": "部署任务已启动", "release_id": release_id}

@router.post("/releases/{release_id}/rollback", summary="回滚版本")
async def rollback_release(
    release_id: str,
    background_tasks: BackgroundTasks,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    回滚到指定版本
    """
    # 检查权限
    if not current_user.has_permission("release:rollback") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限执行回滚"
        )
    
    release = db.query(Release).filter(Release.release_id == release_id).first()
    
    if not release:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="版本发布不存在"
        )
    
    if release.status != "deployed":
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="只能回滚已部署的版本"
        )
    
    # 更新状态为回滚中
    release.status = "rolling_back"
    
    db.commit()
    
    # 记录回滚开始日志
    log = ReleaseLog(
        release_id=release.id,
        action="rollback_started",
        message=f"开始回滚版本 {release.version}",
        user_id=current_user.id,
        status="warning"
    )
    db.add(log)
    db.commit()
    
    # 后台执行回滚任务
    background_tasks.add_task(execute_rollback, release.id, db)
    
    return {"message": "回滚任务已启动", "release_id": release_id}

@router.get("/releases/{release_id}/logs", response_model=List[ReleaseLogSchema], summary="获取发布日志")
async def get_release_logs(
    release_id: str,
    skip: int = Query(0, ge=0, description="跳过记录数"),
    limit: int = Query(50, ge=1, le=200, description="返回记录数"),
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    获取版本发布的操作日志
    """
    # 检查权限
    if not current_user.has_permission("release:read") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限查看发布日志"
        )
    
    release = db.query(Release).filter(Release.release_id == release_id).first()
    
    if not release:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="版本发布不存在"
        )
    
    logs = db.query(ReleaseLog).filter(
        ReleaseLog.release_id == release.id
    ).order_by(ReleaseLog.created_at.desc()).offset(skip).limit(limit).all()
    
    return [ReleaseLogSchema.from_orm(log) for log in logs]

@router.get("/configs", response_model=List[DeploymentConfigSchema], summary="获取部署配置")
async def get_deployment_configs(
    environment: Optional[str] = Query(None, description="环境名称"),
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    获取部署配置列表
    """
    # 检查权限
    if not current_user.has_permission("release:config") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限查看部署配置"
        )
    
    query = db.query(DeploymentConfig)
    
    if environment:
        query = query.filter(DeploymentConfig.environment == environment)
    
    configs = query.order_by(DeploymentConfig.created_at.desc()).all()
    
    return [DeploymentConfigSchema.from_orm(config) for config in configs]

@router.post("/configs", response_model=DeploymentConfigSchema, summary="创建部署配置")
async def create_deployment_config(
    config_data: DeploymentConfigCreate,
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    创建新的部署配置
    """
    # 检查权限
    if not current_user.has_permission("release:config") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限创建部署配置"
        )
    
    # 检查配置是否已存在
    existing_config = db.query(DeploymentConfig).filter(
        DeploymentConfig.name == config_data.name,
        DeploymentConfig.environment == config_data.environment
    ).first()
    
    if existing_config:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="该环境下已存在同名配置"
        )
    
    # 创建配置
    config = DeploymentConfig(
        name=config_data.name,
        environment=config_data.environment,
        config_data=config_data.config_data,
        description=config_data.description,
        created_by=current_user.id,
        is_active=config_data.is_active
    )
    
    db.add(config)
    db.commit()
    db.refresh(config)
    
    return DeploymentConfigSchema.from_orm(config)

@router.get("/stats/summary", summary="获取发布统计")
async def get_release_stats(
    days: int = Query(30, ge=1, le=365, description="统计天数"),
    current_user: User = Depends(get_current_active_user),
    db: Session = Depends(get_db)
):
    """
    获取版本发布统计信息
    """
    # 检查权限
    if not current_user.has_permission("release:read") and not current_user.is_superuser:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="没有权限查看发布统计"
        )
    
    from datetime import timedelta
    start_date = datetime.utcnow() - timedelta(days=days)
    
    # 总发布次数
    total_releases = db.query(Release).filter(Release.created_at >= start_date).count()
    
    # 成功发布次数
    successful_releases = db.query(Release).filter(
        Release.created_at >= start_date,
        Release.status == "deployed"
    ).count()
    
    # 失败发布次数
    failed_releases = db.query(Release).filter(
        Release.created_at >= start_date,
        Release.status == "failed"
    ).count()
    
    # 回滚次数
    rollback_count = db.query(ReleaseLog).filter(
        ReleaseLog.created_at >= start_date,
        ReleaseLog.action == "rollback_completed"
    ).count()
    
    # 成功率
    success_rate = (successful_releases / total_releases * 100) if total_releases > 0 else 0
    
    # 各环境发布统计
    env_stats = db.query(Release.environment, db.func.count(Release.id)).filter(
        Release.created_at >= start_date
    ).group_by(Release.environment).all()
    
    return {
        "total_releases": total_releases,
        "successful_releases": successful_releases,
        "failed_releases": failed_releases,
        "rollback_count": rollback_count,
        "success_rate": round(success_rate, 2),
        "environment_stats": [{"environment": env, "count": count} for env, count in env_stats]
    }

async def execute_deployment(release_id: int, db: Session):
    """
    执行部署任务（后台任务）
    """
    import asyncio
    import random
    
    release = db.query(Release).filter(Release.id == release_id).first()
    if not release:
        return
    
    try:
        # 模拟部署过程
        steps = [
            "准备部署环境",
            "下载代码包",
            "执行构建",
            "运行测试",
            "部署到服务器",
            "健康检查",
            "完成部署"
        ]
        
        for i, step in enumerate(steps):
            # 记录进度日志
            log = ReleaseLog(
                release_id=release.id,
                action="deploy_progress",
                message=f"[{i+1}/{len(steps)}] {step}",
                status="info",
                progress=int((i+1) / len(steps) * 100)
            )
            db.add(log)
            db.commit()
            
            # 模拟执行时间
            await asyncio.sleep(random.uniform(1, 3))
        
        # 模拟成功/失败
        if random.random() > 0.1:  # 90% 成功率
            release.status = "deployed"
            release.deployed_at = datetime.utcnow()
            
            log = ReleaseLog(
                release_id=release.id,
                action="deploy_completed",
                message=f"版本 {release.version} 部署成功",
                status="success",
                progress=100
            )
        else:
            release.status = "failed"
            
            log = ReleaseLog(
                release_id=release.id,
                action="deploy_failed",
                message=f"版本 {release.version} 部署失败",
                status="error",
                progress=100
            )
        
        db.add(log)
        db.commit()
        
    except Exception as e:
        release.status = "failed"
        
        log = ReleaseLog(
            release_id=release.id,
            action="deploy_error",
            message=f"部署过程中发生错误: {str(e)}",
            status="error"
        )
        db.add(log)
        db.commit()

async def execute_rollback(release_id: int, db: Session):
    """
    执行回滚任务（后台任务）
    """
    import asyncio
    import random
    
    release = db.query(Release).filter(Release.id == release_id).first()
    if not release:
        return
    
    try:
        # 模拟回滚过程
        steps = [
            "停止当前服务",
            "备份当前版本",
            "恢复上一版本",
            "重启服务",
            "验证回滚结果"
        ]
        
        for i, step in enumerate(steps):
            log = ReleaseLog(
                release_id=release.id,
                action="rollback_progress",
                message=f"[{i+1}/{len(steps)}] {step}",
                status="warning",
                progress=int((i+1) / len(steps) * 100)
            )
            db.add(log)
            db.commit()
            
            await asyncio.sleep(random.uniform(0.5, 2))
        
        # 回滚成功
        release.status = "rolled_back"
        
        log = ReleaseLog(
            release_id=release.id,
            action="rollback_completed",
            message=f"版本 {release.version} 回滚成功",
            status="success",
            progress=100
        )
        
        db.add(log)
        db.commit()
        
    except Exception as e:
        release.status = "rollback_failed"
        
        log = ReleaseLog(
            release_id=release.id,
            action="rollback_error",
            message=f"回滚过程中发生错误: {str(e)}",
            status="error"
        )
        db.add(log)
        db.commit()